#  /**
#  * Copyright (c) 2022 Beijing Jiaotong University
#  * PhotLab is licensed under [Open Source License].
#  * You can use this software according to the terms and conditions of the [Open Source License].
#  * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
#  *
#  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
#  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
#  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#  *
#  * See the [Open Source License] for more details.
#  */
#  /**
#  * Author: Zheng Wang
#  * Created: Jul. 1, 2022
#  * Supported by: National Key Research and Development Program of China
#  */
import logging

from phot_engine.computing_graph.parameter import Parameter


class Vertex:
    """
        describe a vertex in computing graph
    """

    def __init__(self,
                 vertex_id,
                 phot_lib_class_name,
                 phot_lib_func_name,
                 is_analyzer,
                 parallel_computing_method,
                 vertex_param_list):
        self.vertex_id = vertex_id
        self.__in_edge_iterator = []  # To save vertex's all in edge,content is vertex_id
        self.__out_edge_iterator = []  # To save vertex's all out edge,content is vertex_id
        self.__super_step = 0  # After executing vertex contained phot function,recording super step
        self.__indegree = 0  # indegree of a vertex
        self.__outdegree = 0  # outdegree of a vertex
        self.__is_none_vertex = False  # to judge a vertex is not a none vertex
        if not self.__judge_none_vertex(phot_lib_class_name, phot_lib_func_name):
            self.phot_lib_class_name = phot_lib_class_name  # 底层运算库类名,Components' class name in phot
            self.phot_lib_func_name = phot_lib_func_name  # 底层运算库函数名, Components' function name in phot
            self.parallel_computing_method = parallel_computing_method  # paralle computing method(GPU / CPU)
            self.is_analyzer = is_analyzer  # to judge a vertex is a signal analyzer in GUI or not
            self.vertex_param_dict = self.__gen_param_dict(vertex_param_list)  # python dictionary type,with unit
        else:
            self.is_analyzer = False
            logging.debug("{} is none vertex".format(self.vertex_id))

    def __judge_none_vertex(self, phot_lib_class_name, phot_lib_func_name):
        if (phot_lib_class_name is None) and (phot_lib_func_name is None):
            self.__is_none_vertex = True
            return True
        else:
            self.__is_none_vertex = False
            return False

    def is_none(self):
        return self.__is_none_vertex

    def append_global_system_parameter(self, global_system_parameter_dict: dict):
        if global_system_parameter_dict is not None and len(global_system_parameter_dict) > 0:
            self.vertex_param_dict.update(global_system_parameter_dict)
            logging.debug("Append {} to {}".format(global_system_parameter_dict, self.vertex_id))

    def judge_analyzer(self):
        if self.is_analyzer is not None:
            if "True" == self.is_analyzer or "true" == self.is_analyzer:
                return True
            else:
                return False
        return False

    def get_vertex_id(self):
        return self.vertex_id

    def get_parallel_computing_method(self) -> str:
        return self.parallel_computing_method

    def set_super_step(self, super_step):
        self.__super_step = super_step

    def get_super_step(self):
        return self.__super_step

    def get_out_edge_iterator(self) -> list:
        return self.__out_edge_iterator

    def get_in_edge_iterator(self) -> list:
        return self.__in_edge_iterator

    def get_param_dict(self):
        return self.vertex_param_dict

    def __gen_param_dict(self, param_list):
        """
            generate vertex parameter dict with parameter list
        :param param_list:
        :return:
        """
        res_dict = dict()
        for param in param_list:
            if isinstance(param, Parameter):
                res_dict[param.param_name] = param
            else:
                raise ValueError("element in param_list should be Parameter type not {}".format(type(param_list[0])))
        return res_dict

    def set_indegree(self, indegree):
        self.__indegree = indegree

    def set_outdegree(self, outdegree):
        self.__outdegree = outdegree

    def set_out_edge_iterator(self, edge_list):
        self.__out_edge_iterator = edge_list

    def set_in_edge_iterator(self, edge_list):
        self.__in_edge_iterator = edge_list

    def get_indegree(self):
        return self.__indegree

    def get_outdegree(self):
        return self.__outdegree

    def __repr__(self):
        if not self.__is_none_vertex:
            res_info = "**********Vertex Info**********\n" \
                       "vertex id:{} \n" \
                       "class name:{} \n" \
                       "function name:{} \n" \
                       "is_analyzer:{} \n" \
                       "vertex param list length:{}\n" \
                       "indegree:{}\n" \
                       "outdegree:{}\n" \
                       "**********************\n".format(self.vertex_id,
                                                         self.phot_lib_class_name,
                                                         self.phot_lib_func_name,
                                                         self.is_analyzer,
                                                         len(self.vertex_param_dict),
                                                         self.__indegree,
                                                         self.__outdegree)

            return res_info
        else:
            res_info = """**********Vertex Info**********\n
                            {} is a none vertex.\n
                          **********************\n""".format(self.vertex_id)
            return res_info


if __name__ == '__main__':
    test_parameter_dict_list = [{
        "pyPhotName": "底层运算库中用到的函数参数名",
        "dataType": "float",
        "value": "1.3e2",
        "unit": "m",
        "photUnit": "nm"
    },
        {
            "pyPhotName": "底层运算库中用到的函数参数名",
            "dataType": "float",
            "interval": ["-10", "10"],
            # right open/left open/open/closed
            "intervalStatus": "right open",
            "unit": "db",
            "photUnit": "db"
        }]

    param_list = []
    for elem in test_parameter_dict_list:
        param = Parameter(elem)
        param_list.append(param)

    one_vertex = Vertex(vertex_id="component_id",
                        phot_lib_class_name="phot_class",
                        phot_lib_func_name="func_name",
                        is_analyzer=False,
                        parallel_computing_method="CPU",
                        vertex_param_list=param_list)
    print(one_vertex)
